package metametamodel;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import util.ConstVariables;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.*;

/**
 * @author Junzheng Chen
 * @date 2021/9/22 15:11
 */
public class MetaMetaModel {

    private Document document;

    /**
     * 载入xml对象
     *
     * @param fileName 文件路径
     */
    public void load(String fileName) {
        SAXReader saxReader = new SAXReader();
        try {
            this.document = saxReader.read(new File((fileName)));
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    private String getPackageName() {
        return "package " + ConstVariables.metaModelPackageName + ";";
    }

    private String getClassHeadDoc() {
        return "\n/**\n * @author Junzheng Chen\n */\n\n";
    }

    private Map<String, String> getClassElementTag(List<Attribute> classAttributes) {
        Map<String, String> resMap = new HashMap<>();
        for (Attribute attribute : classAttributes) {
            resMap.put(attribute.getName(), attribute.getData().toString());
        }
        return resMap;
    }

    private String parseClassHead(Map<String, String> classElementTag) {
        StringBuilder res = new StringBuilder();
        res.append("public class ");
        res.append(classElementTag.get("name"));
        res.append(" ");
        if (classElementTag.containsKey("extends")) {
            res.append("extends ");
            res.append(classElementTag.get("extends"));
        }
        return res.toString();
    }

    public MetaMetaModelFileWrapper parseClass(Element classElement) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(getPackageName());
        stringBuilder.append(getClassHeadDoc());
        Map<String, String> classElementTag = getClassElementTag(classElement.attributes());
        assert (classElementTag.containsKey("name"));
        stringBuilder.append(parseClassHead(classElementTag));
        stringBuilder.append("{");
        stringBuilder.append("\n");
        stringBuilder.append("}");
        return new MetaMetaModelFileWrapper(classElementTag.get("name") + ".java", stringBuilder.toString());
    }


    public List<MetaMetaModelFileWrapper> parseClasses() {
        Element classes = this.document.getRootElement();
        List<Element> classElements = classes.elements();
        List<MetaMetaModelFileWrapper> classesFiles = new ArrayList<>();
        for (Element classElement : classElements) {
            if ("class".equals(classElement.getName())) {
                classesFiles.add(parseClass(classElement));
            }

        }
        return classesFiles;
    }

    private void writeNonexistentFileByFileWrappers(String rootPath, MetaMetaModelFileWrapper metaMetaModelFileWrapper) {
        File file = new File(String.valueOf(Paths.get(rootPath, metaMetaModelFileWrapper.fileName)));

        try {
            BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));
            bufferedWriter.write(metaMetaModelFileWrapper.fileContent);
            bufferedWriter.close();
        } catch (IOException e) {
            System.out.println("File Write Failed!");
            e.printStackTrace();
        }
    }

    public void generateMetaModelJavaFileByFileWrapper(List<MetaMetaModelFileWrapper> metaMetaModelFileWrappers) {
        String meteModelPath = Paths.get(ConstVariables.javaPath, ConstVariables.metaModelPathName, "autogen").toString();
        File[] metaModelFile = new File(meteModelPath).listFiles();
        Set<String> fileNames = new HashSet<>();
        if (metaModelFile != null) {
            int n = metaModelFile.length;
            for (File file : metaModelFile) {
                fileNames.add(file.getName());
            }
        }
        for (MetaMetaModelFileWrapper metaMetaModelFileWrapper : metaMetaModelFileWrappers) {
            if (fileNames.contains(metaMetaModelFileWrapper.fileName)) {
                System.out.println("File: " + metaMetaModelFileWrapper.fileName + " is exists, so not create!\n");
            } else {
                writeNonexistentFileByFileWrappers(meteModelPath, metaMetaModelFileWrapper);
            }
        }

    }

}
